/*
 * FSWUniCEUB - 2008
 * 
 * Este arquivo é de propriedade da Fábrica de Software do UniCEUB
 * 
 * Para mais informações entre em contato com a coordenação do
 * curso de Ciência da Computação da instituição.
 */

package br.uniceub.fsw.indicadores.dao;

import br.uniceub.fsw.arquitetura.persistencia.transacao.Transacao;
import br.uniceub.fsw.arquitetura.persistencia.dao.ConstrutorSQL;
import br.uniceub.fsw.arquitetura.persistencia.dao.BaseDAO;
import br.uniceub.fsw.indicadores.vo.DadoPrimarioVO;
import br.uniceub.fsw.indicadores.vo.ValorDadoPrimarioVO;
import br.uniceub.fsw.indicadores.vo.ValorIndicadorVO;
import br.uniceub.fsw.indicadores.vo.IndicadorVO;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Date;

/**
 * Data Access Object da entidade ValorIndicador. Essa classe é responsável por todas as 
 * operações de banco de dados relacionadas à entidade.
 * 
 * @author Filipe Scafuto Vieira RA 20463917
 */
public class ValorIndicadorDAO extends BaseDAO<ValorIndicadorVO> {

    @Override
    public void inserir(ValorIndicadorVO entidade) {

        ConstrutorSQL query = new ConstrutorSQL();

        query.append("INSERT INTO TB_ValorIndicador(VL_ValorIndicador, DT_ValorIndicador, CD_Indicador)");
        query.append("VALUES (?, ?, ?)");

        List<?> parametros = criarParametros(entidade.getVlValorIndicador(),
                entidade.getDtValorIndicador(), entidade.getCdIndicador());

        Integer idGerado = ((Long) executarInsercao(query.toString(), parametros)).intValue();

        entidade.setIdValorIndicador(idGerado);
    }

    @Override
    public void alterar(ValorIndicadorVO entidade) {

        ConstrutorSQL query = new ConstrutorSQL();

        query.append("UPDATE TB_ValorIndicador SET VL_ValorIndicador = ?,");
        query.append("DT_ValorIndicador = ?,");
        query.append("CD_Indicador = ?");
        query.append("WHERE ID_ValorIndicador = ?");

        List<?> parametros = criarParametros(entidade.getVlValorIndicador(),
                entidade.getDtValorIndicador(),entidade.getCdIndicador(),
                entidade.getIdValorIndicador());

        executarAlteracao(query.toString(), parametros);
    }

    @Override
    public void excluir(ValorIndicadorVO entidade) {

        ConstrutorSQL query = new ConstrutorSQL();

        query.append("DELETE FROM TB_ValorIndicador");
        query.append("WHERE ID_ValorIndicador = ?");

        executarAlteracao(query.toString(), criarParametros(entidade.getIdValorIndicador()));
    }

    @Override
    public ValorIndicadorVO consultarPorId(Serializable id) {

        ValorIndicadorVO entidade = null;

        ConstrutorSQL query = new ConstrutorSQL();

        query.append("SELECT * FROM TB_ValorIndicador T WHERE T.ID_ValorIndicador = ?");

        entidade = consultarUm(query.toString(), criarParametros(id));

        return entidade;
    }

    @Override
    public List<ValorIndicadorVO> consultarPorExemplo(ValorIndicadorVO exemplo) {

        List<ValorIndicadorVO> listaRetorno = null;

        ConstrutorSQL query = new ConstrutorSQL();

        query.append("SELECT * FROM TB_ValorIndicador T WHERE 1=1");

        mapearQueryParaExemplo(query, exemplo);

        listaRetorno = consultar(query.toString(), recuperarParametros());

        return listaRetorno;
    }
    
    /**
     * Executa o procedimento de cálculo do indicador. 
     * 
     * @param idIndicador 
     * @param manual indica que o cálculo é instantâneo e não deve ser persistido.
     * @throws java.lang.RuntimeException
     * @throws br.uniceub.fsw.arquitetura.servico.exception.NegocioException
     * @return 
     */
    public ValorIndicadorVO executaProcedimentoCalculoIndicador(IndicadorVO indicador, boolean instantaneo) {
        Float resultado = null;
        ValorIndicadorVO vi = null;
        
        String sql = "CALL " + indicador.getNoProcedimentoCalculoIndicador() + "(" + (instantaneo?"1)":"0)");
        
        try {
            Transacao.iniciar();
            
            indicador.setDtUltimoCalculoIndicador(new Date());
            new IndicadorDAO().alterar(indicador);
            
            ResultSet rs = executarConsulta(sql, null);

            if(rs.next()) {
                vi = new ValorIndicadorVO();

                resultado = new Float(rs.getFloat(1));
                
                vi.setCdIndicador(indicador.getIdIndicador());
                vi.setDtValorIndicador(new Date());
                vi.setVlValorIndicador(resultado);
                
                if(!instantaneo) {
                    new ValorIndicadorDAO().inserir(vi);
                    
                    DadoPrimarioVO dp = new DadoPrimarioVO();
                    dp.setCdIndicador(indicador.getIdIndicador());
                    List<DadoPrimarioVO> dados = new DadoPrimarioDAO().consultarPorExemplo(dp);
                    
                    if(dados != null) {
                        ValorDadoPrimarioDAO vdpDAO = new ValorDadoPrimarioDAO();

                        for(int i = 0; i < dados.size(); i++) {
                            try {
                                resultado = new Float(rs.getFloat(i + 2));

                                ValorDadoPrimarioVO vdp = new ValorDadoPrimarioVO();
                                vdp.setCdDadoPrimario(dados.get(i).getIdDadoPrimario());
                                vdp.setCdValorIndicador(vi.getIdValorIndicador());
                                vdp.setVlValorDadoPrimario(resultado);

                                vdpDAO.inserir(vdp);
                            }
                            catch(SQLException e) {
                                if(e.getErrorCode() == 1305) // Execução não retornou coluna de índice i
                                    i = dados.size(); // ignorar outros
                                else
                                    throw e;
                            }
                        }
                    }
                }
            }
            
            Transacao.efetivar();
        }
        catch (Exception e) {
            Transacao.desfazer();
            throw new RuntimeException("Não foi possível executar procedimento de cálculo: " + e.getMessage());
        }
        
        return vi;
    }

    @Override
    protected ValorIndicadorVO extrairObjetoResultado(ResultSet rs) throws SQLException {

        ValorIndicadorVO entidade = new ValorIndicadorVO();
        
        entidade.setIdValorIndicador(new Integer(rs.getInt("ID_ValorIndicador")));        
        entidade.setVlValorIndicador(new Float(rs.getFloat("VL_ValorIndicador")));
        entidade.setCdIndicador(new Integer(rs.getInt("CD_Indicador")));
        entidade.setDtValorIndicador(rs.getDate("DT_ValorIndicador"));

        return entidade;
    }

    @Override
    protected void mapearQueryParaExemplo(ConstrutorSQL query, ValorIndicadorVO exemplo) {

        if (exemplo.getDtValorIndicador() != null) {
            query.append("AND T.DT_ValorIndicador = ?");
            adicionarParametro(exemplo.getDtValorIndicador());
        }

        if (exemplo.getVlValorIndicador() != null) {
            query.append("AND T.VL_ValorIndicador = ?");
            adicionarParametro(exemplo.getVlValorIndicador());
        }
                
        if (exemplo.getCdIndicador() != null) {
            query.append("AND T.CD_Indicador = ?");
            adicionarParametro(exemplo.getCdIndicador());
        }
    }
}
